﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using DataAccessor.Protector;

namespace DataAccessor
{
    public class HolisticParser
    {
        #region 成员变量
        private readonly XmlDocument _holisticXML;
        private Holistic _holistic;
        private HolisticDatabase[] _databaseArray;
        private static object PARSER_LOCK = new object();
        #endregion

        #region 构造函数
        /// <summary>
        /// 从指定的Holistic文件创建HolisticParser的一个实例
        /// </summary>
        public HolisticParser(XmlDocument holisticXML)
        {
            lock (PARSER_LOCK)
            {
                _holisticXML = holisticXML;
                Parser();
            }
        }

        /// <summary>
        /// 从指定的Holistic文件创建HolisticParser的一个实例
        /// </summary>
        public HolisticParser(string holisticFile)
        {
            lock (PARSER_LOCK)
            {
                _holisticXML = new XmlDocument();
                LoadHolistic(holisticFile);
                Parser();
            }
        }
        #endregion

        #region 公共函数
        /// <summary>
        /// 修改连接字符串
        /// </summary>
        /// <param name="databaseName">数据库配置节的名称</param>
        /// <param name="connectionString">新连接字符串</param>
        /// <returns>修改成功-true；修改失败-false.</returns>
        public bool ChangeDatabaseConnectionString(string databaseName, string connectionString)
        {
            if (!_databaseArray.Any(d => d.Name.Equals(databaseName, StringComparison.CurrentCultureIgnoreCase)))
            {
                return false;
            }
            _databaseArray.Single(d => d.Name.Equals(databaseName, StringComparison.CurrentCultureIgnoreCase)).ConnectionString = connectionString;
            var databaseNode = _holisticXML.SelectSingleNode(string.Format("/Holistic/Database[@Name='{0}']", databaseName));
            if (databaseName == null)
            {
                return false;
            }

            databaseNode.Attributes["ConnectionString"].Value = connectionString;
            _holisticXML.Save(AppDomain.CurrentDomain.BaseDirectory + @"\App_Data\T-SQL\Holistic.xml");
            return true;
        }
        #endregion

        #region 私有函数
        /// <summary>
        /// 加载Holistic文件到XMLDocument
        /// </summary>
        /// <param name="holisticFile"></param>
        private void LoadHolistic(string holisticFile)
        {
            if (string.IsNullOrEmpty(holisticFile))
            {
                throw new NullReferenceException("无法从空的TSQL配置文件路径解析文件。");
            }

            if (!File.Exists(holisticFile))
            {
                throw new FileNotFoundException("没有找到文件：" + holisticFile);
            }

            try
            {
                _holisticXML.Load(holisticFile);
            }
            catch (Exception ex)
            {
                throw new Exception("Holistic.xml解析失败", ex);
            }
        }

        /// <summary>
        /// 解析XML文件
        /// </summary>
        private void Parser()
        {
            var bytes = UnicodeEncoding.UTF8.GetBytes(_holisticXML.InnerXml);
            Stream stream = new MemoryStream(bytes);

            XmlSerializer serializer = new XmlSerializer(typeof(Holistic));
            try
            {
                _holistic = serializer.Deserialize(stream) as Holistic;
            }
            catch (Exception ex)
            {
                throw new Exception("反序列化Holistic.xml失败", ex);
            }
            finally
            {
                stream.Close();
                stream.Dispose();
            }

            // 如果节点配置了保护算法，则解密连接字符串
            foreach (var database in _holistic.Database)
            {
                if (!string.IsNullOrEmpty(database.Protector))
                {
                    IProtector protector = CreateProtector(database.Protector);
                    database.ConnectionString = protector.DecryptConnectionString(database.ConnectionString);
                }
            }
        }

        /// <summary>
        /// 创建保护算法的实例
        /// </summary>
        /// <param name="protector">保护算法的名称，来自Holistic.xml文件的Database节点的Protector属性。</param>
        /// <returns>保护算法的实例</returns>
        public static IProtector CreateProtector(string protector)
        {
            if (string.IsNullOrWhiteSpace(protector))
            {
                return null;
            }
            var accessorType = Type.GetType(protector);
            return Activator.CreateInstance(accessorType) as IProtector;
        }
        #endregion

        #region 属性
        /// <summary>
        /// 获取所有模块的集合
        /// </summary>
        public HolisticDatabase[] DatabaseArray
        {
            get { return _holistic.Database; }
        }

        public Holistic Holistic
        {
            get { return _holistic; }
        }
        #endregion
    }
}
